﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Markup;

namespace Geometry
{
    public sealed class RadicalLine : GObjectBase, IGLine
    {
        public RadicalLine()
        {
        }

        public RadicalLine(IGCircle _circle1, IGCircle _circle2)
        {
            this.Circle1 = _circle1;
            this.Circle2 = _circle2;
        }


        protected override void ReleaseDependencies()
        {
            this.Circle1 = null;
            this.Circle2 = null;
        }

        protected override void UpdateBoundingBox()
        {
        }

        private IGCircle m_Circle1;
        [ValueSerializer(typeof(ElementReferenceSerializer))]
        [TypeConverter(typeof(PlaceHolderTypeConverter))]
        public IGCircle Circle1
        {
            get
            {
                return m_Circle1;
            }
            set
            {
                if (m_Circle1 == value) return;

                if (m_Circle1 != null) m_Circle1.PropertyChanged -= new PropertyChangedEventHandler(_related_PropertyChanged);
                m_Circle1 = value;
                if (m_Circle1 != null) m_Circle1.PropertyChanged += new PropertyChangedEventHandler(_related_PropertyChanged);

                RaisePropertyChanged("Circle1");
                UpdateCalculations();
            }
        }

        private IGCircle m_Circle2;
        [ValueSerializer(typeof(ElementReferenceSerializer))]
        [TypeConverter(typeof(PlaceHolderTypeConverter))]
        public IGCircle Circle2
        {
            get
            {
                return m_Circle2;
            }
            set
            {
                if (m_Circle2 == value) return;

                if (m_Circle2 != null) m_Circle2.PropertyChanged -= new PropertyChangedEventHandler(_related_PropertyChanged);
                m_Circle2 = value;
                if (m_Circle2 != null) m_Circle2.PropertyChanged += new PropertyChangedEventHandler(_related_PropertyChanged);

                RaisePropertyChanged("Circle2");
                UpdateCalculations();
            }
        }

        private double m_Slope;
        public double Slope
        {
            get
            {
                return m_Slope;
            }
            private set
            {
                // TODO:    following comment is a workaround for a bug, 
                //          whereintersection point doesn't change if line changes but intersection is constant
                // if (m_Slope == value) return;
                m_Slope = value;
                RaisePropertyChanged("Slope");
            }
        }

        void _related_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName != "Centre" && e.PropertyName != "Radius") return;

            UpdateCalculations();
        }

        private void UpdateCalculations()
        {
            if (m_Circle1.IsNullOrPlaceHolder() || m_Circle2.IsNullOrPlaceHolder()) return;

            Vector centralLine = m_Circle1.Centre - m_Circle2.Centre;
            double d = (centralLine.LengthSquared + m_Circle1.Radius * m_Circle1.Radius - m_Circle2.Radius * m_Circle2.Radius) / (2 * centralLine.Length);
            this.Point1 = m_Circle1.Centre - centralLine.ToUnit() * d;
            Vector p = new Vector(-centralLine.Y, centralLine.X);
            this.Point2 = this.Point1 + p;

            this.Slope = ((Point2.Y - Point1.Y) / (Point2.X - Point1.X));
        }

        private Point m_RadicalCentre;
        public Point Point1
        {
            get
            {
                return m_RadicalCentre;
            }
            private set
            {
                if (value.Equals(m_RadicalCentre)) return;
                m_RadicalCentre = value;
                RaisePropertyChanged("Point1");
            }
        }

        private Point m_PerpendicularHelper;
        public Point Point2 {
            get
            {
                return m_PerpendicularHelper;
            }
            private set
            {
                if (value.Equals(m_PerpendicularHelper)) return;
                m_PerpendicularHelper = value;
                RaisePropertyChanged("Point2");
            }
        }


    }
}
